package znet

import (
	"fmt"
	"gitee.com/hufengjiu/go-zinx/utils"
	"gitee.com/hufengjiu/go-zinx/ziface"
	"log"
	"net"
)

type Server struct {
	Name            string
	IPVersion       string
	IP              string
	Port            int
	mux             ziface.IMux
	workers         Workers
	ConnManager     ziface.IConnManager
	OnConnStartFunc func(ziface.IConnection)
	OnConnStopFunc  func(ziface.IConnection)
}

func (s *Server) SetOnConnStart(callback func(ziface.IConnection)) {
	s.OnConnStartFunc = callback
}

func (s *Server) SetOnConnStop(callback func(ziface.IConnection)) {
	s.OnConnStopFunc = callback
}

func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStartFunc != nil {
		s.OnConnStartFunc(conn)
	}
}

func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStopFunc != nil {
		s.OnConnStopFunc(conn)
	}
}

func (s *Server) Start() {
	log.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)
	log.Printf("[Zinx] Version: %s, MaxConn: %d,  MaxPacketSize: %d\n",
		utils.GlobalConf.Version,
		utils.GlobalConf.MaxConn,
		utils.GlobalConf.MaxPacketSize)

	s.mux.StartWorkers()

	addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
	if err != nil {
		log.Println("resolve tcp error ", err)
		return
	}

	listener, err := net.ListenTCP(s.IPVersion, addr)
	if err != nil {
		log.Println("listen error", err)
		return
	}

	var connId uint32 = 0
	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			log.Println("accept error", err)
			continue
		}

		if s.ConnManager.Len() > utils.GlobalConf.MaxConn {
			conn.Close()
			continue
		}
		connId++
		c := NewConnection(s, conn, connId, s.mux)
		go c.Start()
	}

}

func (s *Server) Stop() {
	log.Println("[Stop] server, name ", s.Name)
	s.ConnManager.ClearConn()
}

func (s *Server) Serve() {
	s.Start()
	select {}
}

func NewServer() *Server {
	s := &Server{
		Name:        utils.GlobalConf.Name,
		IPVersion:   "tcp4",
		IP:          utils.GlobalConf.Host,
		Port:        utils.GlobalConf.TcpPort,
		workers:     make([]Worker, 10),
		ConnManager: NewConnManager(),
	}
	s.mux = NewMux(s.workers)
	return s
}

func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.mux.AddRouter(msgId, router)
}

func (s *Server) GetConnManager() ziface.IConnManager {
	return s.ConnManager
}
